#!/usr/bin/env python
# -*- coding: utf-8 -*-

'''Command-line utility for browsing Descript.ion and desc.utf files


'''

import os
import sys
import codecs
import re
import mimetypes
import subprocess

import d2utf
import write_utf

class Descriptor:

    def __init__(self):

        self.Writer = write_utf.write_gen()
        self.type_dict = {}
        self.verbose = False
        self.s_full = False

    def check_int(self, word):
        '''Check if string could be turned into integer'''
        try:
            int(word)
            return True
        except ValueError:
            return False
       
    def del_desc(self, f_name):
        '''delete entry from desc.utf'''
        fin = []
        desc = self.read_dir()
        if self.check_int(f_name):
            # arg is an integer
            d_lst = self.dict2list(desc)
            print 'deleting description for ', d_lst[int(f_name)][0]
            d_lst.pop(int(f_name))
        else:
            # agr is a string
            desc.pop(f_name)
            print 'deleting description for ', f_name
            d_lst = self.dict2list(desc)
        for entry in d_lst:
            if entry[1]:
                fin.append((entry[0] + '||' +  entry[1] + '\n').decode('utf8'))
                
        self.Writer.write_file('desc.utf', fin)

    def dict2list(self, desc):
        '''turn dictionary into ordered list, plus sort dirs and files'''

        desc_list = desc.items()
        dirs = []
        files = []

        for i in desc_list:
            if '/' in i[0]:
                dirs.append(i)
            else:
                files.append(i)

        dirs.sort()
        files.sort()
        desc_list = dirs + files
        return desc_list

    def f_assoc(self):
        """Get file-associations"""

        home = os.path.expanduser('~')
        fp = open(os.path.join(home, '.comb.bindings'), "r")
        bind_lst = fp.readlines()
        fp.close()

        # dictionary of file-types and associated applications

        for x in bind_lst:
            if not '#' in x:
                line_lst = x.split()
                arg_ls = []
                for m in range(1, len(line_lst)):
                    arg_ls.append(line_lst[m])
                    self.type_dict[line_lst[0]] = arg_ls

            else:
                continue
            line_lst = []
        if debug == 1:
            print self.type_dict

#        return self.type_dict

    def get_path(self):
        """Form a list of all files in directory"""

        pth = os.getcwd()
        full_ls = os.listdir(pth)
        for i in range(len(full_ls)):
            if os.path.isdir(full_ls[i]):
                full_ls[i] = '/' + full_ls[i] 
        full_ls.sort()
        return full_ls


    def read_dir(self):
        """Read filenames and comments.
        
        If there is any text-file of supported type, read. Create a dictionary 
        of filenames and comments. Include names of files, that have no 
        comments to them.
        
        """

        full_ls = self.get_path()
        desc_tmp = {}
        desc = {}
        if 'desc.utf' in full_ls: 
            if self.verbose:
                print "reading from desc.utf"        
            fp = codecs.open('desc.utf', "rb", "utf8")
            try:
                desc_lns = fp.readlines()
            except UnicodeDecodeError:
                print 'wrong encoding'
                desc_lns = ''
            fp.close()
            
            for x in desc_lns:
                # have to encode strings, else unicode filenames will be 
                # duplicated by 'setdefault' dict method (see below).
                lst = x.encode('utf8').strip().split('||')
                try:
                    if lst[0] in full_ls:
                        if lst[1]:
                    
                            # fill in main dictionary
                            desc[lst[0]] = lst[1]
                    else:
                        print 'desc contains filename, missing in directory: ', lst[0]
                
                except IndexError:
                    print 'desc.utf file is probably corrupted. Wrong separator?' 
            # insert missing file names
            for y in full_ls:
                # if there is no 'y' in desc, it is inserted
                desc.setdefault(y, '')

            return desc
        
        # Parse old file, created by FAR.
        elif 'Descript.ion' in full_ls:
            if self.verbose:
                print "No desc.utf found, in", full_ls, "reading Descript.ion."

            # d2utf module function. Parses Descript.ion
            desc = d2utf.desc_func(full_ls)
            for j in desc:
                if not j in full_ls:
                    print 'missing file!', j

            for y in full_ls:
                desc.setdefault(y, '')
            return desc            

        else:        
            if self.verbose:
                print "no desc.utf found, creating empty"

            os.mknod('desc.utf')

            # reread the directory
            full_ls = self.get_path()

            for j in full_ls:
                desc[j] = "" 
            
            return desc            

    def run_file(self, f_name):
        '''Run file with assotiated programm'''

        self.f_assoc()

        if self.check_int(f_name):
            desc = self.read_dir()
            desc_lst = self.dict2list(desc)
            f_name = desc_lst[int(f_name)][0]

        path_ls = []
        f_path = os.path.join(os.getcwd(), f_name)
        mime = mimetypes.guess_type(f_path)[0]
        if debug == 1:
            print 'mime', mime
        if mime:
            res = re.search(r"(.*)/(.*)", mime).groups()
            type = res[0]
            if type == "application":
                type = res[1]
            if debug == 1:
                print 'type', type
        else:
            print 'unknown file type'
            return 1

        print self.type_dict.items()
        for j in self.type_dict.items():
            if j[0] == type:
                # prog_ls - programm name and its arguments (list)
                prog_ls = j[1]

        if prog_ls == [] and f_name[0:1] != '/':
            print 'unknown file type'
            return 1

        [path_ls.append(z) for z in prog_ls]
        path_ls.append(f_path)
        print path_ls
        subprocess.Popen(path_ls)
        return 0

    def search_word(self, word):
        '''search for given word in directory, recursively'''

        patt = re.compile(word, re.U | re.I)

        res = []

        for root, dirs, files in os.walk(os.getcwd()):

            os.chdir(root)
            desc = self.read_dir()

            if desc: 
                desc_lst = self.dict2list(desc)
                for f_name, comm in desc_lst:
                    if patt.search(comm.decode('utf8')):
                        res.append((root, f_name, comm))
                    if self.s_full:
                        if patt.search(f_name.decode('utf8')):
                            res.append((root, f_name, comm))

        return res

    def write_desc(self, f_name, comm):
        '''add entry to dict/list, write to desc.utf'''

        fin = []
        desc = self.read_dir()

        # if 1st arg is integer, get f_name
        if self.check_int(f_name):

            desc_lst = self.dict2list(desc)
            num = int(f_name)
            popped = desc_lst.pop(num)
            desc_lst.append((popped[0], comm))
            desc_lst.sort()

            print 'adding description for ', popped[0]
            
        else:
            if os.path.isdir(f_name):
                f_name = '/' + f_name
            if desc.has_key(f_name):
                print 'adding description for ', f_name
                desc[f_name] = comm
                desc_lst = self.dict2list(desc)
            else:
                print 'wrong file name'
                return

        for entry in desc_lst:
            # write only entries with comment
            if entry[1]:
                fin.append((entry[0] + '||' +  entry[1] + '\n').decode('utf8'))

        self.Writer.write_file('desc.utf', fin)

############## MAIN #############################

if __name__ == '__main__':

    global debug
    debug = 1

    main_cl = Descriptor()

    argv = sys.argv

    if len(argv)>1:
        if argv[1] == "-d":
            # delete entry from desc.utf
            main_cl.del_desc(argv[2])

        elif argv[1] == "-e":
            # run file with corresponding programm
            main_cl.run_file(argv[2])

        elif argv[1] == "-f":
            # full list of files

            desc_list = main_cl.dict2list(main_cl.read_dir())

            for num in range(len(desc_list)):
                line = desc_list[num][0]
                comm = desc_list[num][1]
                if comm:
                    print num, line, ' == ', comm
                else:
                    print num, line

#        elif argv[1] == "-h":
#
#            fp = open('lookd_help_EN.txt', 'r')
#            hlp = readline()
#            fp.close()
#
#            print hlp

        elif argv[1] == "-s" or argv[1] == "-S":
            # search for entry in parent dirs
            if argv[1] == "-S":
                # search in file names also, not only in comments
                main_cl.s_full = True
            try:
                s_res = main_cl.search_word(argv[2].decode('utf8'))
                for root, f_name, comm in s_res:
                    print os.path.join(root, f_name), ' == ', comm
            except IndexError:
                print 'no string to search given'

        elif argv[1] == '-w':
            # write line to desc.utf
            try:
                main_cl.write_desc(argv[2], argv[3])
            except IndexError:
                print 'no comment given'

        else:
            # look up description for given filename
            desc = main_cl.read_dir()
            look_name = argv[1] 
            try:
                print look_name + ' || ' + desc[look_name]
            except KeyError:
                print 'NO such file in directory'
    else:
        # no args => output short list - only commented files

        desc_list = main_cl.dict2list(main_cl.read_dir())

        for num in range(len(desc_list)):
            line = desc_list[num][0]
            comm = desc_list[num][1]
            if comm:
                print num, line, ' == ', comm

